/*
 * GDataValidator.java
 * Created on 30 déc. 07
 *
 * Glacéo Internet Platform
 * http://sourceforge.net/projects/chm/
 *
 * Copyright (c) 2005-2007, Jan Janke (VirtualHockey Project)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.hockeo.vhbase.utils.data;

import com.hockeo.vhbase.data.dao.IGDao;
import com.hockeo.vhbase.data.dao.contest.GContestElement;
import com.hockeo.vhbase.data.dao.season.GMatchday;
import com.hockeo.vhbase.error.GDataValidationException;

/**
 * Utility class which provides methods for validating data which may have been passed to
 * the application, e.g. in an HTML request.
 *
 * @version $Id$
 * @author jjanke
 */
public class GDataValidator
{
  private IGDao d_dao;

  public final IGDao getDao()
  {
    return d_dao;
  }

  public final void setDao( IGDao dao )
  {
    d_dao = dao;
  }

  /**
   * Validates a parameter that is expected to be an integer.
   *
   * @param strParamName the name of the parameter
   * @param strValue the received value (<code>null</code> is only permitted if the
   *          default value is not <code>null</code>)
   * @param nDefault the default value to be used if the received value is
   *          <code>null</code> or if the value is less than the accepted minimum or
   *          greater than the accepted maximum
   * @param nMin the minimum accepted value (pass <code>null</code> to avoid checking for
   *          a minimum)
   * @param nMax the maximum accepted value (pass <code>null</code> to avoid checking for
   *          a maximum)
   * @return the received value as integer
   * @throws GDataValidationException if the value is <code>null</code> and no default
   *           value is specified or if the received value is not a valid integer or if
   *           the value is not in the allowed range
   */
  public int validateInteger( String strParamName, String strValue, Integer nDefault, Integer nMin, Integer nMax )
      throws GDataValidationException
  {
    int nVal;

    if ( strValue == null && nDefault == null )
      throw new GDataValidationException( strParamName, strValue, "NULL is not allowed." );

    if ( strValue == null )
      return nDefault.intValue();

    try
    {
      nVal = Integer.parseInt( strValue );
    }
    catch ( NumberFormatException ex )
    {
      throw new GDataValidationException( strParamName, strValue, "The provided value is not a valid integer." );
    }

    if ( nMin != null && nVal < nMin.intValue() )
      if ( nDefault == null )
        throw new GDataValidationException( strParamName, strValue,
            "The provided value is less than the accepted minimum of " + nMin.intValue() );
      else
        nVal = nDefault.intValue();

    if ( nMax != null && nVal > nMax.intValue() )
      if ( nDefault == null )
        throw new GDataValidationException( strParamName, strValue,
            "The provided value is greater than the accepted maximum of " + nMax.intValue() );
      else
        nVal = nDefault.intValue();

    return nVal;
  }

  /**
   * Validates the specified matchday and returns it if it exists.
   *
   * @param element the contest element for which to retrieve the matchday
   * @param strParamName the name of the parameter the matchday was passed in with
   * @param nMatchdayNum the matchday number as string
   * @return the found matchday if the validation succeeds
   * @throws GDataValidationException if the validation fails
   */
  public GMatchday validateMatchday( GContestElement element, String strParamName, Integer nMatchdayNum )
      throws GDataValidationException
  {
    GMatchday matchday = null;

    if ( nMatchdayNum == null )
      throw new GDataValidationException( strParamName, null, "NULL is not allowed as matchday!" );

    try
    {
      matchday = d_dao.findMatchday( element, nMatchdayNum );
    }
    catch ( NumberFormatException ex )
    {
      throw new GDataValidationException( strParamName, nMatchdayNum.toString(), "The provided matchday is not a number.", ex );
    }

    if ( matchday == null )
      throw new GDataValidationException( strParamName, nMatchdayNum.toString(),
          "The matchday does not exist for the contest element " + element.getId() );

    return matchday;
  }

  /**
   * Validates the specified matchday and returns it if it exists.
   *
   * @param element the contest element for which to retrieve the matchday
   * @param strParamName the name of the parameter which was used to collect the matchday
   *          number
   * @param strMatchdayNum the matchday number as string (e.g. as retrieved from an HTML
   *          request).
   * @return the found matchday if the validation succeeds
   * @throws GDataValidationException if the validation fails
   */
  public GMatchday validateMatchday( GContestElement element, String strParamName, String strMatchdayNum )
      throws GDataValidationException
  {
    GMatchday matchday = null;

    if ( strMatchdayNum == null )
      throw new GDataValidationException( strParamName, strMatchdayNum, "NULL is not allowed as matchday!" );

    try
    {
      matchday = d_dao.findMatchday( element, Integer.parseInt( strMatchdayNum ) );
    }
    catch ( NumberFormatException ex )
    {
      throw new GDataValidationException( strParamName, strMatchdayNum, "The provided matchday is not a number.", ex );
    }

    if ( matchday == null )
      throw new GDataValidationException( strParamName, strMatchdayNum,
          "The matchday does not exist for the contest element " + element.getId() );

    return matchday;
  }

  /**
   * Tries to load the entity of the specified type and having the given ID.
   *
   * @param classEntity the persistent entity class
   * @param strParamName the name of the request parameter which supplies the entity ID
   * @param strEntityId the ID (must be the primary key) of the entity
   * @return the found entity if the validation succeeds
   * @throws GDataValidationException if the validation fails
   */
  public <T> T validateEntity( Class<T> classEntity, String strParamName, String strEntityId )
      throws GDataValidationException
  {
    if ( strEntityId == null )
      throw new GDataValidationException( strParamName, strEntityId, "NULL is not allowed as value for the parameter "
          + strParamName );

    T entity = d_dao.findEntity( classEntity, strEntityId );

    if ( entity == null )
      throw new GDataValidationException( strParamName, strEntityId, "The entity of type " + classEntity.getName()
          + " with the ID " + strEntityId + " does not exist." );

    return entity;
  }

  /**
   * Tries to load the entity of the specified type and having the given ID.
   *
   * @param classEntity the persistent entity class
   * @param strParamName the name of the request parameter which supplies the entity ID
   * @param nEntityId the ID (must be the primary key) of the entity
   * @return the found entity if the validation succeeds
   * @throws GDataValidationException if the validation fails
   */
  public <T> T validateEntity( Class<T> classEntity, String strParamName, Integer nEntityId )
      throws GDataValidationException
  {
    if ( nEntityId == null )
      throw new GDataValidationException( strParamName, String.valueOf( nEntityId ),
          "NULL is not allowed as value for the parameter " + strParamName );

    T entity = d_dao.findEntity( classEntity, nEntityId );

    if ( entity == null )
      throw new GDataValidationException( strParamName, String.valueOf( nEntityId ), "The entity of type "
          + classEntity.getName() + " with the ID " + nEntityId + " does not exist." );

    return entity;
  }

  /**
   * Validates the enumeration value.
   *
   * @param classEnum the enumeration class the read value should belong to
   * @param strParamName the parameter name
   * @param strValue the value to be validated
   * @return the matching enum constant
   * @throws GDataValidationException if the the validation fails
   */
  public <T extends Enum<T>> T validateEnumValue( Class<T> enumClass, String strParamName, String strValue )
      throws GDataValidationException
  {
    if ( strValue == null )
      throw new GDataValidationException( strParamName, strValue, "NULL is not allowed for the parameter "
          + strParamName );

    try
    {
      return Enum.valueOf( enumClass, strValue );
    }
    catch ( Exception ex )
    {
      throw new GDataValidationException( strParamName, strValue,
          "The value is not recognized as valid enum constant of type " + enumClass.getClass().getName() );
    }
  }
}
